import query
import cache
import push

from cache import login_required, get_time, sockets

import json


def sign_in(request):
    username = request['username']
    password = request['password']
    # authenticate
    user = query.authenticate(username, password)
    if not user:
        return {'result': 'ERROR_USER_UNAUTHORIZED'}
    if not cache.can_login_in(user.username):
        return {'result': 'ERROR_USER_ALREADY_ONLINE'}
    token = cache.get_user_token(username)
    success, failure, score = query.get_history(username)
    # update cache
    cache.cache_session.waiting_users.set(username, score)
    cache.cache_session.online_users.set(username, [get_time(), token])
    # render response
    response = {
        'result': 'ok',
        'success': success,
        'failure': failure,
        'score': score,
        'token': token
    }
    return response


def sign_up(request):
    username = request['username']
    password = request['password']
    # email
    user = query.create_user(username, password)
    if isinstance(user, str):
        response = {'result': user}
    else:  # isinstance(user, User):
        response = {'result': 'ok'}
    return response


def reset_password(request):
    username = request['username']
    old_password = request['old_password']
    new_password = request['new_password']
    # authenticate
    user = query.authenticate(username, old_password)
    if not user:
        response = {'result': 'ERROR_INVALID_PASSWORD'}
        return response
    query.set_password(user, new_password)
    response = {'result': 'ok'}
    return response


@login_required
def set_ready(request):
    username = request['username']
    ready = int(request['ready'])
    # get cache
    user_info = cache.cache_session.partner_users.get(username)
    if user_info is None:
        return {'result': 'ERROR_PARTNER_NOT_FOUND'}
    partner_name = user_info[0]
    partner_info = cache.cache_session.partner_users.get(partner_name)
    if user_info is None:
        return {'result': 'ERROR_USER_OFFLINE'}
    # start game
    if ready and int(partner_info[1]):
        role = cache.start_game(username, partner_name)
        push.push_game_start(username, role)
        push.push_game_start(partner_name,  - role)
    else:
        user_info[1] = ready
        cache.cache_session.partner_users.set(username, user_info)
        push.push_ready(partner_name, ready)  # send to user's partner
    # render response
    response = {
        'result': 'ok'
    }
    return response


@login_required
def change_partner(request):
    username = request['username']
    former_partner_info = cache.cache_session.partner_users.get(username)
    if former_partner_info is None:
        return {'result': 'ERROR_USER_OFFLINE'}
    former_partner = former_partner_info[0]
    new_partner_a = cache.get_new_partner(username, former_partner)
    if not (new_partner_a and len(new_partner_a)):
        return {'result': 'ok'}
    # get new partner
    push.push_partner_changed(username, new_partner_a)
    push.push_partner_changed(new_partner_a, username)
    new_partner_b = cache.partner_leave(former_partner)
    if not (new_partner_b and len(new_partner_b)):
        return {'result': 'ok'}
    # former partner get new partner
    push.push_partner_changed(former_partner, new_partner_b)
    push.push_partner_changed(new_partner_b, former_partner)
    return {'result': 'ok'}


@login_required
def new_step(request):
    username = request['username']
    x = int(request['x'])
    y = int(request['y'])
    partner_info = cache.cache_session.playing_users.get(username)
    if partner_info is None:
        return {'result': 'ERROR_USER_OFFLINE'}
    push.push_new_step(partner_info[0], x, y)
    response = {
        'result': 'ok'
    }
    return response


@login_required
def retract_ask(request):
    username = request['username']
    partner_info = cache.cache_session.playing_users.get(username)
    if partner_info is None:
        return {'result': 'ERROR_USER_OFFLINE'}
    push.push_retract_ask(partner_info[0])
    response = {
        'result': 'ok'
    }
    return response


@login_required
def retract_answer(request):
    username = request['username']
    permission = int(request['permission'])
    partner_info = cache.cache_session.playing_users.get(username)
    if partner_info is None:
        return {'result': 'ERROR_USER_OFFLINE'}
    push.push_retract_answer(partner_info[0], permission)
    response = {
        'result': 'ok'
    }
    return response


@login_required
def resign(request):
    username = request['username']
    partner_info = cache.cache_session.playing_users.get(username)
    if partner_info is None:
        return {'result': 'ERROR_USER_OFFLINE'}
    cache.end_game(username, partner_info[0])
    query.resign_update_history(username, partner_info[0])
    push.push_resign(partner_info[0])
    response = {
        'result': 'ok'
    }
    return response


@login_required
def sign_out(request):
    username = request['username']
    cache.force_offline(username)
    sockets[username].close()
    response = {
        'result': 'ok'
    }
    return response


if __name__ == '__main__':
    pass
    # sign up
    result = sign_up({'username': 'finley', 'password': 'abcd'})
    print(result)
    result = sign_up({'username': 'finley', 'password': 'abcd'})
    print(result)
    # reset password
    result = reset_password({'username': 'finley', 'old_password': 'abcd', 'new_password': '1234'})
    print(result)
    result = reset_password({'username': 'finley', 'old_password': 'abcd', 'new_password': '1234'})
    print(result)
    # sign in
    result = sign_in({'username': 'finley', 'password': '1234', 'socket': None})
    print(result)
    result = sign_in({'username': 'finley', 'password': '1234', 'socket': None})
    print(result)
